{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0f84611f-5f01-4dc6-ba6b-abefedaeaa61",
   "metadata": {},
   "source": [
    "Chapter 02\n",
    "\n",
    "# 自定义函数计算矩阵乘法\n",
    "《线性代数》 | 鸢尾花书：数学不难"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bed0075-4769-46aa-8ee6-c6c449b83284",
   "metadata": {},
   "source": [
    "这段代码的主要任务是从数学角度实现**矩阵乘法**（Matrix Multiplication）的过程，并验证其在不同矩阵顺序下的结果。以下是对代码的详细数学解释：\n",
    "\n",
    "---\n",
    "\n",
    "### 1. **矩阵乘法的基本原理**\n",
    "\n",
    "设有两个矩阵 $A \\in \\mathbb{R}^{m \\times p}$ 和 $B \\in \\mathbb{R}^{p \\times n}$，它们的乘积定义为一个新的矩阵 $C \\in \\mathbb{R}^{m \\times n}$，满足：\n",
    "\n",
    "$$\n",
    "C_{ij} = \\sum_{k=1}^{p} A_{ik} \\cdot B_{kj}, \\quad \\text{其中 } 1 \\leq i \\leq m,\\ 1 \\leq j \\leq n\n",
    "$$\n",
    "\n",
    "这意味着，$C$ 的第 $i$ 行第 $j$ 列的元素是 $A$ 的第 $i$ 行和 $B$ 的第 $j$ 列的**点积**。\n",
    "\n",
    "---\n",
    "\n",
    "### 2. **代码实现的数学对应**\n",
    "\n",
    "定义的函数 `matrix_multiplication(A, B)` 实际上就是实现上述公式的计算方式：\n",
    "\n",
    "- 首先获取矩阵 $A$ 和 $B$ 的形状分别为 $(m, p_A)$ 和 $(p_B, n)$。\n",
    "- 然后检查是否满足矩阵乘法的条件，即 $p_A = p_B$，对应数学上的 $A \\in \\mathbb{R}^{m \\times p}$ 和 $B \\in \\mathbb{R}^{p \\times n}$。\n",
    "- 接着创建零矩阵 $C \\in \\mathbb{R}^{m \\times n}$。\n",
    "- 使用三重循环实现：\n",
    "\n",
    "$$\n",
    "\\text{for } i = 0 \\text{ to } m-1:\\\\\n",
    "\\quad \\text{for } j = 0 \\text{ to } n-1:\\\\\n",
    "\\quad\\quad \\text{for } k = 0 \\text{ to } p-1:\\\\\n",
    "\\quad\\quad\\quad C[i,j] \\mathrel{+}= A[i,k] \\cdot B[k,j]\n",
    "$$\n",
    "\n",
    "该循环逐元素计算并累加 $C_{ij}$ 的值，和上述数学定义完全一致。\n",
    "\n",
    "---\n",
    "\n",
    "### 3. **具体矩阵的构造与运算**\n",
    "\n",
    "矩阵 $A$ 被定义为：\n",
    "\n",
    "$$\n",
    "A = \\begin{bmatrix}\n",
    "1 & 2 & 3 \\\\\n",
    "4 & 5 & 6\n",
    "\\end{bmatrix} \\in \\mathbb{R}^{2 \\times 3}\n",
    "$$\n",
    "\n",
    "然后取其转置得到：\n",
    "\n",
    "$$\n",
    "B = A^\\top = \\begin{bmatrix}\n",
    "1 & 4 \\\\\n",
    "2 & 5 \\\\\n",
    "3 & 6\n",
    "\\end{bmatrix} \\in \\mathbb{R}^{3 \\times 2}\n",
    "$$\n",
    "\n",
    "再进行两次矩阵乘法：\n",
    "\n",
    "#### (1) $A \\cdot B$\n",
    "\n",
    "$$\n",
    "A \\cdot B = \\begin{bmatrix}\n",
    "1 & 2 & 3 \\\\\n",
    "4 & 5 & 6\n",
    "\\end{bmatrix}\n",
    "\\cdot\n",
    "\\begin{bmatrix}\n",
    "1 & 4 \\\\\n",
    "2 & 5 \\\\\n",
    "3 & 6\n",
    "\\end{bmatrix}\n",
    "= \\begin{bmatrix}\n",
    "1\\cdot1 + 2\\cdot2 + 3\\cdot3 & 1\\cdot4 + 2\\cdot5 + 3\\cdot6 \\\\\n",
    "4\\cdot1 + 5\\cdot2 + 6\\cdot3 & 4\\cdot4 + 5\\cdot5 + 6\\cdot6\n",
    "\\end{bmatrix}\n",
    "= \\begin{bmatrix}\n",
    "14 & 32 \\\\\n",
    "32 & 77\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "#### (2) $B \\cdot A$\n",
    "\n",
    "$$\n",
    "B \\cdot A = \\begin{bmatrix}\n",
    "1 & 4 \\\\\n",
    "2 & 5 \\\\\n",
    "3 & 6\n",
    "\\end{bmatrix}\n",
    "\\cdot\n",
    "\\begin{bmatrix}\n",
    "1 & 2 & 3 \\\\\n",
    "4 & 5 & 6\n",
    "\\end{bmatrix}\n",
    "= \\begin{bmatrix}\n",
    "1\\cdot1 + 4\\cdot4 & 1\\cdot2 + 4\\cdot5 & 1\\cdot3 + 4\\cdot6 \\\\\n",
    "2\\cdot1 + 5\\cdot4 & 2\\cdot2 + 5\\cdot5 & 2\\cdot3 + 5\\cdot6 \\\\\n",
    "3\\cdot1 + 6\\cdot4 & 3\\cdot2 + 6\\cdot5 & 3\\cdot3 + 6\\cdot6\n",
    "\\end{bmatrix}\n",
    "= \\begin{bmatrix}\n",
    "17 & 22 & 27 \\\\\n",
    "22 & 29 & 36 \\\\\n",
    "27 & 36 & 45\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "---\n",
    "\n",
    "### 4. **总结**\n",
    "\n",
    "本代码实现的是基础线性代数中最核心的运算之一：**矩阵乘法**，其数学本质是将一个矩阵的行向量与另一个矩阵的列向量进行点积。由于使用的是纯 Python 的循环方式（而不是 NumPy 的矢量化计算），这也帮助我们直观理解矩阵乘法的底层运算逻辑，尤其对学习者理解以下公式至关重要：\n",
    "\n",
    "$$\n",
    "C_{ij} = \\sum_{k=1}^{p} A_{ik} \\cdot B_{kj}\n",
    "$$\n",
    "\n",
    "这个公式是整个函数 `matrix_multiplication` 的核心。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62554c66-72b0-4680-8498-2c1f4b7de75f",
   "metadata": {},
   "source": [
    "## 初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4726c405-d63a-42cd-b391-471764ec75b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25ce6457-d6c3-4c33-93f7-0311dad3d710",
   "metadata": {},
   "source": [
    "## 自定义函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "311e7aee-b415-47ec-9971-a16921c77ce4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def matrix_multiplication(A, B):\n",
    "\n",
    "    # 获取矩阵 A 和 B 的形状\n",
    "    m, p_A = A.shape\n",
    "    p_B, n = B.shape\n",
    "\n",
    "    # 检测矩阵形状是否符合矩阵乘法规则\n",
    "    if p_A != p_B:\n",
    "        raise ValueError('Dimensions do not match')\n",
    "\n",
    "    # 初始化结果矩阵 C，形状 (m, n)，初始值设为 0\n",
    "    C = np.zeros((m, n))\n",
    "\n",
    "    # 进行矩阵乘法计算，使用三层 for 循环\n",
    "    for i in range(m):        # 遍历 A 的行\n",
    "        for j in range(n):    # 遍历 B 的列\n",
    "            for k in range(p_A):  # 遍历 A 的列 / B 的行\n",
    "                C[i, j] += A[i, k] * B[k, j]  # 逐元素累加\n",
    "\n",
    "    return C"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d7cf1d6-3406-4c65-8860-eb9c555c2e46",
   "metadata": {},
   "source": [
    "## 定义矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "615efd21-d4c7-41b6-9827-481d11fec522",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = np.array([[1, 2, 3],\n",
    "              [4, 5, 6]])\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "1aa1a8c3-7fae-453c-9016-8ce410ef9f7f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 4],\n",
       "       [2, 5],\n",
       "       [3, 6]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "B = A.T\n",
    "B"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b540f553-e9fe-44bf-88dd-05c8b83efecd",
   "metadata": {},
   "source": [
    "## 矩阵乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "1ce432ee-3cf1-468e-820e-825b581820e1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[14., 32.],\n",
       "       [32., 77.]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "matrix_multiplication(A, B)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "513aaf4c-f3a6-4362-a628-3c0bb729faef",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[17., 22., 27.],\n",
       "       [22., 29., 36.],\n",
       "       [27., 36., 45.]])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "matrix_multiplication(B, A)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8dae950-44ce-4a9e-893f-c6cbd84cc502",
   "metadata": {},
   "source": [
    "作者\t**生姜DrGinger**  \n",
    "脚本\t**生姜DrGinger**  \n",
    "视频\t**崔崔CuiCui**  \n",
    "开源资源\t[**GitHub**](https://github.com/Visualize-ML)  \n",
    "平台\t[**油管**](https://www.youtube.com/@DrGinger_Jiang)\t\t\n",
    "\t\t[**iris小课堂**](https://space.bilibili.com/3546865719052873)\t\t\n",
    "\t\t[**生姜DrGinger**](https://space.bilibili.com/513194466)  "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
